/*
 * Copyright 2012-2013 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.spddr.pmos;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory;
import org.hibernate.cfg.Environment;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.auditing.CurrentDateTimeProvider;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import cn.seqdata.tags.Point;
import cn.seqdata.tags.common.IdTags;
import cn.seqdata.tsdb.drds.cell.CellTemplate;

import com.spddr.pmos.jpa.Plant;
import com.spddr.pmos.repos.PlantRepos;

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", basePackageClasses = PlantRepos.class)
@EnableJpaAuditing(auditorAwareRef = "auditorAware", dateTimeProviderRef = "dateTimeProvider")
public class JpaConfiguration extends JpaBaseConfiguration {

	@Primary
	@Bean(name = "dataSource")
	@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
	public BasicDataSource dataSource() {
		return new BasicDataSource();
	}

	@Bean(name = "cellTemplate")
	public CellTemplate<IdTags, Point<IdTags>> cellTemplate(@Qualifier("dataSource") DataSource ds) {
		return new CellTemplate<IdTags, Point<IdTags>>(ds);
	}

	@Override
	protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
		return new HibernateJpaVendorAdapter();
	}

	/** 多个jpa共用属性 */
	@Bean(name = "vendorProperties")
	public Map<String, Object> vendorProperties() {
		Map<String, Object> properties = new HashMap<>();

		//Hibernate要求！不添加会导致延迟加载时session已经失效
		properties.put(Environment.ENABLE_LAZY_LOAD_NO_TRANS, true);
		properties.put(Environment.IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS, true);

		properties.put(Environment.USE_SECOND_LEVEL_CACHE, true);
		properties.put(Environment.CACHE_REGION_FACTORY, SingletonEhCacheRegionFactory.class.getName());

		return properties;
	}

	@Override
	protected Map<String, Object> getVendorProperties() {
		return vendorProperties();
	}

	@Primary
	@Bean(name = "entityManagerFactory")
	public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder,
		@Qualifier("dataSource") DataSource dataSource) {
		return factoryBuilder.dataSource(dataSource).packages(Plant.class).properties(getVendorProperties())
			.jta(isJta()).build();
	}

	@Primary
	@Bean(name = "transactionManager")
	public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory emf) {
		return new JpaTransactionManager(emf);
	}

	@Bean
	public AuditorAware<Long> auditorAware() {
		return new AuditorAware<Long>() {

			@Override
			public Long getCurrentAuditor() {
				return 0L;
			}
		};
	}

	@Bean
	public DateTimeProvider dateTimeProvider() {
		return CurrentDateTimeProvider.INSTANCE;
	}
}
